use chrono::prelude::*;
use chrono::Days;
use chrono::Local;
use chrono::Months;
use chrono::NaiveDate;
use regex::Regex;
use std::time::{Duration, UNIX_EPOCH};

use super::my_err::MyErr;

/// 当前时间戳，毫秒
pub fn now_milliseconds() -> i64 {
    let now = Local::now();
    now.timestamp_millis()
}

/// 当前时间戳，秒
pub fn now_seconds() -> i64 {
    let now = Local::now();
    now.timestamp()
}

/// 获取当前日期字符串,格式 2023-03-05
/// ```rust
/// use chrono::prelude::*;
///
/// let date_time: DateTime<Utc> = Utc.with_ymd_and_hms(2017, 04, 02, 12, 50, 32).unwrap();
/// let formatted = format!("{}", date_time.format("%d/%m/%Y %H:%M"));
/// assert_eq!(formatted, "02/04/2017 12:50");
/// ```
#[allow(dead_code)]
pub fn get_now_day() -> String {
    let now = Local::now();
    now.format("%Y-%m-%d").to_string()
}

/// 获取当前月份字符串,格式 2023-03
/// ```rust
/// use chrono::prelude::*;
///
/// let date_time: DateTime<Utc> = Utc.with_ymd_and_hms(2017, 04, 02, 12, 50, 32).unwrap();
/// let formatted = format!("{}", date_time.format("%d/%m/%Y %H:%M"));
/// assert_eq!(formatted, "02/04/2017 12:50");
/// ```
#[allow(dead_code)]
pub fn get_now_month() -> String {
    let now = Local::now();
    now.format("%Y-%m").to_string()
}

/// 获取当前年份字符串,格式 2023
/// ```rust
/// use chrono::prelude::*;
///
/// let date_time: DateTime<Utc> = Utc.with_ymd_and_hms(2017, 04, 02, 12, 50, 32).unwrap();
/// let formatted = format!("{}", date_time.format("%d/%m/%Y %H:%M"));
/// assert_eq!(formatted, "02/04/2017 12:50");
/// ```
#[allow(dead_code)]
pub fn get_now_year() -> String {
    let now = Local::now();
    now.format("%Y").to_string()
}

/// 根据格式获取当前日期字符串,如： %Y-%m-%d 得到结果： 2023-03-05
/// ```rust
/// use chrono::prelude::*;
///
/// let date_time: DateTime<Utc> = Utc.with_ymd_and_hms(2017, 04, 02, 12, 50, 32).unwrap();
/// let formatted = format!("{}", date_time.format("%d/%m/%Y %H:%M"));
/// assert_eq!(formatted, "02/04/2017 12:50");
/// ```
#[allow(dead_code)]
pub fn get_now_by_format(fmt: &str) -> String {
    let now = Local::now();
    now.format(fmt).to_string()
}

/// 判断字符串是否日期格式(2023-05-16)
#[allow(dead_code)]
pub fn is_day(s: &str) -> bool {
    if let Ok(re) = Regex::new("^\\d{4}-\\d{2}-\\d{2}$") {
        re.is_match(s)
    } else {
        false
    }
}

/// 判断字符串是否日期格式(2023-05)
#[allow(dead_code)]
pub fn is_month(s: &str) -> bool {
    if let Ok(re) = Regex::new("^\\d{4}-\\d{2}$") {
        re.is_match(s)
    } else {
        false
    }
}

/// 把时间格式的字符串转为时间戳（毫秒）
/// fmt ： ”%Y-%m-%d %H:%M“   => 2019-02-08 23:06
/// str_to_milliseconds("2019-02-08 23:06:02", "%Y-%m-%d %H:%M:%S")
/// 如果 to_cst 为 true，则转化后的值则为减去 8 小时后的值。
#[allow(dead_code)]
pub fn str_to_milliseconds(s: &str, fmt: &str, to_cst: bool) -> i64 {
    if s.len() > 10 {
        // 如果日期字符串大于 10 个字符，应该是包含了时分秒，所以需要使用 NaiveDateTime 解析
        if let Ok(t) = NaiveDateTime::parse_from_str(s, fmt) {
            if to_cst {
                t.and_utc().timestamp_millis() - 28800000
            } else {
                t.and_utc().timestamp_millis()
            }
        } else {
            0
        }
    } else {
        // 否正应该是只有年月日，需要使用 NaiveDate 解析
        if let Ok(t) = NaiveDate::parse_from_str(s, fmt) {
            if let Some(nt) = t.and_hms_opt(0, 0, 0) {
                if to_cst {
                    nt.and_utc().timestamp_millis() - 28800000
                } else {
                    nt.and_utc().timestamp_millis()
                }
            } else {
                0
            }
        } else {
            0
        }
    }
}

/// 字符串转日期格式的字符串
/// ```
/// let s1 = "2021.2.04";
/// let s2 = "2021/3/5";
/// let s3 = "2023.8-24";
/// let s4 = "2023-03.4";
/// let s5 = "2023/03.41";
///
/// assert_eq!("2021-02-04", util_date::str_to_day(s1));
/// assert_eq!("2021-03-05", util_date::str_to_day(s2));
/// assert_eq!("2023-08-24", util_date::str_to_day(s3));
/// assert_eq!("2023-03-04", util_date::str_to_day(s4));
/// assert_eq!("", util_date::str_to_day(s5));month_str
///
/// ```
///
#[allow(dead_code)]
pub fn str_to_day(s: &str) -> String {
    let sv: Vec<&str> = s.split_terminator(&['-', '.', '/'][..]).collect();
    if sv.len() == 3 {
        let year = sv[0].parse::<i32>().unwrap_or_default();
        let month = sv[1].parse::<i32>().unwrap_or_default();
        let day = sv[2].parse::<i32>().unwrap_or_default();

        if year > 1970 && year < 2999 && month > 0 && month < 13 && day > 0 && day < 32 {
            return format!("{}-{:02}-{:02}", year, month, day);
        }
    }
    return "".to_string();
}

/// 把时间戳（毫秒）转为时间格式的字符串
/// fmt ： ”%Y-%m-%d %H:%M“   => 2019-02-08 23:06
/// str_to_milliseconds("2019-02-08 23:06", "%Y-%m-%d %H:%M")
#[allow(dead_code)]
pub fn milliseconds_to_str(t: i64, fmt: &str) -> String {
    let d = UNIX_EPOCH + Duration::from_millis((t + 28800000) as u64); // 强行加上8个小时，变为北京时间
    let datetime = DateTime::<Utc>::from(d);
    return datetime.format(fmt).to_string();
}

/// 两个日期相减，得到相差的天数
/// end_day - start_day
#[allow(dead_code)]
pub fn days_by_day_differ(end_day: &str, start_day: &str) -> i32 {
    if is_day(end_day) && is_day(start_day) {
        let dt1 = str_to_milliseconds(end_day, "%Y-%m-%d", false);
        let dt2 = str_to_milliseconds(start_day, "%Y-%m-%d", false);
        let day = (dt1 - dt2) / (24 * 60 * 60 * 1000);
        return day as i32;
    } else {
        return 0;
    }
}

/// 两个日期相减，得到相差的月数
/// end_day - start_day
#[allow(dead_code)]
pub fn months_by_day_differ(end_day: &str, start_day: &str) -> Result<u32, MyErr> {
    let d1_v = start_day.split("-").into_iter().map(|v| v.parse::<i32>().unwrap_or_default()).collect::<Vec<i32>>();
    let d2_v = end_day.split("-").into_iter().map(|v| v.parse::<i32>().unwrap_or_default()).collect::<Vec<i32>>();

    log::info!("\n\n\n {:?}-{:?} \n\n\n", d1_v, d2_v);

    if d1_v.len() == 3 && d2_v.len() == 3 {
        let s_y = d1_v[0];
        let s_m = d1_v[1];
        let s_d = d1_v[2];
        let e_y = d2_v[0];
        let e_m = d2_v[1];
        let e_d = d2_v[2];

        // 如果开始日期的号数（2024年10月6号，的6号）大于1,则结束日期的号数必须为小于1的数，如：6-1=5,2025年8月5号
        // 如果开始日期的号数（2024年10月1号，的1号）等于1,则结束日前必须是结束月的最后一天，如：2025年9月30号中的30
        let z_d = if s_d > 1 {
            (s_d - 1) as u32
        } else {
            last_day_of_month(e_y as u32, e_m as u32)?
        };

        if z_d == e_d as u32 {
            let m = (e_y - s_y) * 12 + (e_m - s_m);
            let n = if (e_d - s_d) > 20 { m + 1 } else { m };
            if n > 0 {
                Ok(n as u32)
            } else {
                Err(MyErr::Msg(format!("两个时间相差无几！")))
            }
        } else {
            Err(MyErr::Msg(format!("不准确的到期时间，起租至停租时间必须是完整月份的！")))
        }
    } else {
        Err(MyErr::Msg(format!("错误的时间格式！")))
    }
}

/// 给日期（d，格式：2023-08-22）添加对应的年，月，日，并返回添加后的日期（格式：YYYY-mm-dd）
/// 注意：该方法先add 天，再add月份，最后add年。
/// ```
/// util_date::day_add("2012-8-30", 1, 1, 1)
/// = 2013-9-30
///
/// // 1:2012-08-30 增加1天 => 2012-08-31
/// // 2:2012-08-31 增加1月 => 2012-09-31 因为9月没有31日，所以取最后一天变为 2012-09-30
/// // 2:2012-09-30 增加1年 => 2013-09-30 即最终结果
/// ```
///
#[allow(dead_code)]
pub fn day_add(day: &str, y: i32, m: i32, d: i32) -> String {
    if let Ok(mut t) = NaiveDate::parse_from_str(day, "%Y-%m-%d") {
        if m > 0 {
            t = t.checked_add_months(Months::new(m as u32)).unwrap_or_default();
        } else if m < 0 {
            t = t.checked_sub_months(Months::new(m.abs() as u32)).unwrap_or_default();
        }

        if d > 0 {
            t = t.checked_add_days(Days::new(d as u64)).unwrap_or_default();
        } else if d < 0 {
            t = t.checked_sub_days(Days::new(d.abs() as u64)).unwrap_or_default();
        }

        let mut oy = t.year();

        if y != 0 {
            oy += y;
        }

        format!("{}-{:02}-{:02}", oy, t.month(), t.day())
    } else {
        day.to_string()
    }
}

/// 根据月份获取该月份最后一天
pub fn get_month_last_day(month: &str) -> Result<String, MyErr> {
    if is_month(month) {
        let v = month.split("-").into_iter().map(|v| v.parse::<i32>().unwrap_or_default()).collect::<Vec<i32>>();
        let days = days_in_month(v[0], v[1] as u32);
        Ok(format!("{}-{}", month, days))
    } else {
        Err(MyErr::Msg("错误的月份格式".to_string()))
    }
}

/// 判断某个月份有多少天
pub fn days_in_month(year: i32, month: u32) -> i32 {
    match month {
        2 => {
            if (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0) {
                29 // 如果是闰年，‌二月有29天
            } else {
                28 // 否则二月有28天
            }
        }
        1 | 3 | 5 | 7 | 8 | 10 | 12 => 31,
        4 | 6 | 9 | 11 => 30,
        _ => 0,
    }
}

/// 根据年，月获得此月份最后一天(天数)
pub fn last_day_of_month(year: u32, month: u32) -> Result<u32, MyErr> {
    // 创建该月的第一天的日期

    if year > 1970 && year < 2999 && month > 0 && month < 13 {
        let (y, m) = if month == 12 { (year + 1, 1) } else { (year, month + 1) };

        let opt = NaiveDate::from_ymd_opt(y as i32, m, 1);
        if let Some(prev_month_first_day) = opt {
            let last_day_of_month = prev_month_first_day - chrono::Duration::days(1);
            Ok(last_day_of_month.day())
        } else {
            Err(MyErr::Msg("日前格式错误".to_string()))
        }
    } else {
        Err(MyErr::Msg("错误的年份或月份".to_string()))
    }
}

/// 根据日期获取 年，季度，月
pub fn get_year_quarter_month_by_day(day: &str) -> Result<(String, String, String), MyErr> {
    if is_day(day) {
        let sv: Vec<&str> = day.split_terminator(&['-', '.', '/'][..]).collect();
        if sv.len() == 3 {
            let year_val = sv[0].parse::<i32>().unwrap_or_default();
            let month_val = sv[1].parse::<i32>().unwrap_or_default();
            let day_val = sv[2].parse::<i32>().unwrap_or_default();

            if year_val > 1970 && year_val < 2999 && month_val > 0 && month_val < 13 && day_val > 0 && day_val < 32 {
                let year_str = format!("{}", year_val);
                let quarter_str = match month_val {
                    1 | 2 | 3 => format!("{}-一", year_val),
                    4 | 5 | 6 =>  format!("{}-二", year_val),
                    7 | 8 | 9 =>  format!("{}-三", year_val),
                    10 | 11 | 12 =>  format!("{}-四", year_val),
                    _ => format!("{}-一", year_val) 
                };
                let month_str = format!("{}-{:02}", year_val, month_val);
                Ok((year_str, quarter_str, month_str))
            } else {
                Err(MyErr::Msg("错误的日期格式".to_string()))
            }
        } else {
            Err(MyErr::Msg("错误的日期格式".to_string()))
        }
    } else {
        Err(MyErr::Msg("错误的日期格式".to_string()))
    }
}

/// 格式化日期
/// format_day("2025-04-02", "%Y年%m月%d日")  ->  2025年04月02日
pub fn format_day(day: &str, fmt: &str) -> String {
    let t = str_to_milliseconds(day, "%Y-%m-%d", false); 
    if t > 9999999 {
        return milliseconds_to_str(t, fmt);
    } else {
        return "".to_string();
    }
    
}